﻿#If WINDOWS And (Not NETFX_CORE) Then
Imports System.Windows.Forms
Imports System.Windows.Forms.ListViewItem
Imports System.ComponentModel
Imports Runa.Common.Helper

Namespace Global.System.Windows.Forms

    Public Module Extension
        Public Delegate Function SetPropertyCallback(Of T)(ByRef Ctrl As Control, ByVal Value As T) As Boolean
        Public Delegate Function SetPropertyCallback(Of U, V)(ByRef Ctrl As Control, ByVal Value As U, ByVal p As V) As Boolean

        <Extension()> _
        Public Function SetText(ByRef Ctrl As Control, ByVal [Text] As String) As Boolean
            If Ctrl.InvokeRequired Then
                Dim d As New SetPropertyCallback(Of String)(AddressOf SetText)
                Return Ctrl.Invoke(d, New Object() {Ctrl, [Text]})
            Else
                Ctrl.Text = [Text]
                Return True
            End If
        End Function

        <Extension()> _
        Public Function SetEnable(ByRef Ctrl As Control, ByVal Value As Boolean) As Boolean
            If Ctrl.InvokeRequired Then
                Dim d As New SetPropertyCallback(Of Boolean)(AddressOf SetEnable)
                Return Ctrl.Invoke(d, New Object() {Ctrl, Value})
            Else
                Ctrl.Enabled = Value
                Return True
            End If
        End Function

        <Extension()> _
        Public Function SetChecked(ByRef Ctrl As CheckBox, ByVal Value As Boolean) As Boolean
            If Ctrl.InvokeRequired Then
                Dim d As New SetPropertyCallback(Of Boolean)(AddressOf SetChecked)
                Return Ctrl.Invoke(d, New Object() {Ctrl, Value})
            Else
                Ctrl.Checked = Value
                Return True
            End If
        End Function

        <Extension()> _
        Public Function SetTopMost(ByRef Ctrl As Form, ByVal Value As Boolean) As Boolean
            If Ctrl.InvokeRequired Then
                Dim d As New SetPropertyCallback(Of Boolean)(AddressOf SetTopMost)
                Return Ctrl.Invoke(d, New Object() {Ctrl, Value})
            Else
                Ctrl.TopMost = Value
                Return True
            End If
        End Function

        <Extension()> _
        Public Function AddItem(Of T)(ByRef Ctrl As ListBox, ByVal Item As T, Optional ByVal predictor As Predicate(Of T) = Nothing) As Boolean
            If predictor(Item) = False Then Return False
            If Ctrl.InvokeRequired Then
                Dim d As New SetPropertyCallback(Of Object, Predicate(Of T))(AddressOf AddItem)
                Return Ctrl.Invoke(d, New Object() {Ctrl, Item, predictor})
            Else
                Ctrl.Items.Add(Item)
                Return True
            End If
        End Function

        <Extension()> _
        Public Function RemoveItem(ByRef Ctrl As ListBox, ByVal Item As Object) As Boolean
            If Ctrl.InvokeRequired Then
                Dim d As New SetPropertyCallback(Of Object)(AddressOf RemoveItem)
                Return Ctrl.Invoke(d, New Object() {Ctrl, Item})
            Else
                Ctrl.Items.Remove(Item)
                Return True
            End If
        End Function

        <Extension()> _
        Public Function ToString(ByRef item As ListViewItem, Optional ByVal delim As String = ", ") As String
            Dim lst As New List(Of String)
            lst.Add(item.Text)
            For Each i As ListViewSubItem In item.SubItems
                lst.Add(i.Text)
            Next i
            Return lst.ToArray().ToString(delim)
        End Function

        <Extension()> _
        Public Sub RemoveAll(ByRef colletion As System.Windows.Forms.ListBox.ObjectCollection)
            For Each item In colletion
                colletion.Remove(item)
            Next item
        End Sub

        <Extension()> _
        Public Function RemoveIf(Of T)(ByVal [Me] As System.Windows.Forms.ListBox.ObjectCollection, ByVal predict As Func(Of T, Boolean)) As Boolean
            For Each item In [Me]
                If predict(item) Then
                    [Me].Remove(item)
                    Return True
                End If
            Next
            Return False
        End Function

        <Extension()> _
        Public Function ToArray(Of T)(ByVal [Me] As System.Windows.Forms.ListBox.ObjectCollection) As T()
            Dim lst As New List(Of T)
            For Each item As Object In [Me]
                lst.Add(GenericCast(Of Object, T)(item))
            Next
            Return lst.ToArray()
        End Function

        <Extension()> _
        Public Sub Sort(Of T As IComparable(Of T))(ByVal [Me] As System.Windows.Forms.ListBox)
            If [Me].Items.Count = 0 Then Exit Sub
            Dim lst([Me].Items.Count - 1) As T
            [Me].Items.CopyTo(lst, 0)
            Array.Sort(lst)
            [Me].Items.Clear()
            For Each item In lst
                [Me].Items.Add(item)
            Next
        End Sub

        <Extension()> _
        Public Sub Cancel(ByVal [Me] As BackgroundWorker)
            If [Me].IsBusy = True Then
                [Me].CancelAsync()
                While [Me].IsBusy
                    Application.DoEvents()
                    Threading.Thread.Sleep(100)
                End While
            End If
        End Sub

    End Module

End Namespace

#End If